﻿using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using Microsoft.SqlServer.Management.Smo;
using System.Windows.Forms;
//using Microsoft.SqlServer.Management.Smo; // 2005
using Microsoft.SqlServer.Management.Sdk.Sfc; // 2008

namespace DBSourceToolsLib.SysObjects
{
    public class SODependencyTree : Interfaces.IDisplayPanel
    {
        DatabaseEx m_Database;
        SysObjects m_ParentSysObjects;
        List<string> m_ErrorList = new List<string>();

        public SODependencyTree(DatabaseEx oDatabase, SysObjects oParentSysObjects)
        {
            this.m_Database = oDatabase;
            this.m_ParentSysObjects = oParentSysObjects;
        }
        private List<SysObject> m_DependencyTree = new List<SysObject>();
        public List<SysObject> DependencyTree
        {
            get { return this.m_DependencyTree; }
        }


        public void LoadFromDisk()
        {
            
            string strFilePath = this.m_ParentSysObjects.SourceBaseDirectory + "\\Dependencies\\Tree.txt";
            if (System.IO.File.Exists(strFilePath))
            {
                using (System.IO.StreamReader oReader = new System.IO.StreamReader(strFilePath))
                {
                    string strLine;
                    while ((strLine = oReader.ReadLine()) != null)
                    {
                        string strType = strLine.Substring(0, strLine.IndexOf("."));
                        string strObject = strLine.Substring(strType.Length +1);
                        SysObject oSysObject = this.m_ParentSysObjects.getSysObject(strType + "s", strObject);
                        this.m_DependencyTree.Add(oSysObject);
                    }
                }
            }

        }
        public void LoadFromDatabase(EventHandler<ProgressEventArgs> localHandler)
        {
            m_ErrorList.Clear();
            int iProcessed = 0;
            int iTotalCount = 0;

            if (localHandler != null)
                localHandler(this, new ProgressEventArgs(0, 100,
                    "Processing Dependencies ..." ));

            Microsoft.SqlServer.Management.Smo.Server oServer;
            if (!System.String.IsNullOrEmpty(this.m_Database.UserName))
            {
                Microsoft.SqlServer.Management.Common.ServerConnection oConn =
                    new Microsoft.SqlServer.Management.Common.ServerConnection(this.m_Database.DataSourceName,
                        this.m_Database.UserName, this.m_Database.Password);
                oServer = new Microsoft.SqlServer.Management.Smo.Server(oConn);
            }
            else
            {
                oServer = new Microsoft.SqlServer.Management.Smo.Server(this.m_Database.DataSourceName);
            }

            //Microsoft.SqlServer.Management.Common.ServerConnection oConn =
            //    new Microsoft.SqlServer.Management.Common.ServerConnection("192.168.0.87", "sa", "sa_password");
            ////Microsoft.SqlServer.Management.Smo.Server oServer = new Microsoft.SqlServer.Management.Smo.Server(this.m_Database.DataSourceName);
            //Microsoft.SqlServer.Management.Smo.Server oServer = new Microsoft.SqlServer.Management.Smo.Server(oConn);

            //Server oServer = new Server(this.m_Database.DataSourceName);
            Microsoft.SqlServer.Management.Smo.Database oMDatabase = oServer.Databases[this.m_Database.DatabaseName];

            Scripter oScripter = new Scripter(oServer);

            UrnCollection oColl = new Microsoft.SqlServer.Management.Smo.UrnCollection();

            foreach (SysObject oSysObject in this.m_ParentSysObjects.SysObjectsList.Values)
            {
                switch (oSysObject.Type)
                {
                    case SysObjectType.Schema:
                    case SysObjectType.User:
                    case SysObjectType.Role:
                        break;
                    case SysObjectType.Trigger:
//                        oColl.Add(new Urn(oSysObject.Urn));
                        break;
                    default: {
                        if (!String.IsNullOrEmpty(oSysObject.Urn))
                            oColl.Add(new Urn(oSysObject.Urn));
                        break;
                    }
                }
                
                    
            }

            if (oColl.Count > 0) // this may be a blank database.
            {
                Microsoft.SqlServer.Management.Smo.DependencyTree oTree = oScripter.DiscoverDependencies(oColl, true);

                DependencyWalker oWalker = new DependencyWalker();
                //oWalker.DiscoveryProgress += new ProgressReportEventHandler(oWalker_DiscoveryProgress);

                this.m_DependencyTree.Clear();
                DependencyCollection oDepColl = oWalker.WalkDependencies(oTree);
                IEnumerator<DependencyCollectionNode> oEnumDepColl = oDepColl.GetEnumerator();
                iTotalCount = oDepColl.Count;

                while (oEnumDepColl.MoveNext())
                {
                    DependencyCollectionNode oDep = oEnumDepColl.Current;
                    System.Console.WriteLine(oDep.Urn.ToString());
                    UrnParser oParser = new UrnParser(oDep.Urn);

                    if (localHandler != null)
                        localHandler(this, new ProgressEventArgs(iProcessed++, iTotalCount,
                            "Processing Dependency " + oParser.getObjectName()));

                    if (oParser.getTypeName().CompareTo("XmlSchema") != 0)
                    {
                        SysObject oSysObject = this.m_ParentSysObjects.getSysObject(oParser.getTypeName() + "s", oParser.getObjectName());
                        if (oSysObject == null)
                        {
                            // some urns may be unresolved entities.
                            // am ignoring these to start with.
                            if (!oDep.Urn.ToString().Contains("/UnresolvedEntity"))
                                m_ErrorList.Add("Could not parse Urn :" + oDep.Urn);
                            //MessageBox.Show("no dep for " + oDep.Urn);
                        }
                        else
                        {
                            if (oParser.getTypeName().CompareTo("Schema") == 0)
                            {
                                m_ErrorList.Add("Could not parse Urn :" + oDep.Urn);
                                //MessageBox.Show("no dep for " + oDep.Urn);
                            }
                            this.m_DependencyTree.Add(oSysObject);
                        }
                    }

                }
            }
            // 3.5 way:
            //foreach (DependencyCollectionNode oDep in oDepColl.ToList())
            //{
            //    System.Console.WriteLine(oDep.Urn.ToString());
            //    UrnParser oParser = new UrnParser(oDep.Urn);
            //    SysObject oSysObject = this.m_ParentSysObjects.getSysObject(oParser.getTypeName() + "s", oParser.getObjectName());
            //    this.m_DependencyTree.Add(oSysObject);
            //}

        }
        public void Clear()
        {
            this.m_DependencyTree.Clear();
        }

        public string Text
        {
            get
            {
                StringBuilder oBuilder = new StringBuilder();
                foreach (SysObject oSysObject in this.m_DependencyTree)
                {
                    if (oSysObject != null)
                    {
                        oBuilder.AppendLine(oSysObject.QualifiedName);
                    }
                }
                return oBuilder.ToString();
            }
        }

        internal void Write()
        {
            string strFilePath = this.m_ParentSysObjects.SourceBaseDirectory + "\\Dependencies\\Tree.txt";
            if (!System.IO.Directory.Exists(this.m_ParentSysObjects.SourceBaseDirectory + "\\Dependencies"))
            {
                System.IO.Directory.CreateDirectory(this.m_ParentSysObjects.SourceBaseDirectory + "\\Dependencies");
            }
            FileUtils.EnsureFileIsWriteable(strFilePath);
            using (System.IO.StreamWriter oWriter = new System.IO.StreamWriter(strFilePath))
            {
                foreach (SysObject oSysObject in this.m_DependencyTree)
                {
                    if (oSysObject != null)
                        oWriter.WriteLine(oSysObject.QualifiedName);
                }
            }
            
        }

        //internal void aWriteCreateScripts(DatabaseEx sourceDatabase
        //    , string strDatabasesXmlFile // 
        //    , string strBaseBinDir
        //    )
        //{
        //    if (strBaseBinDir == null)
        //        strBaseBinDir = UserSettings.Instance().StartupPath;
        //    if (!System.IO.Directory.Exists(this.m_ParentSysObjects.SourceBaseDirectory))
        //        System.IO.Directory.CreateDirectory(this.m_ParentSysObjects.SourceBaseDirectory);

        //    using (System.IO.StreamWriter oStreamWriter = new System.IO.StreamWriter(
        //        this.m_ParentSysObjects.SourceBaseDirectory + "\\Run_Create_Scripts.bat"))
        //    {
        //        // write settings
        //        oStreamWriter.WriteLine("set DB_BASE_DIR=" + sourceDatabase.BaseDirectory + "\\");
        //        oStreamWriter.WriteLine("rem");

        //        //if (this.m_ParentSysObjects.ScriptOptions.ScriptDropAndCreate)
        //        //{
        //        //    // first write this parent's drop and create scripts
        //        //    oStreamWriter.WriteLine("sqlcmd -S " + m_Database.DataSourceName + " -E -i " + m_Database.DropScript.ScriptFilePath);
        //        //    oStreamWriter.WriteLine("sqlcmd -S " + m_Database.DataSourceName + " -E -i " + m_Database.CreateScript.ScriptFilePath);
        //        //}


        //        // schemas are not included in the dependency tree
        //        foreach (SOSchema oSchema in this.m_ParentSysObjects.Schemas)
        //        {
        //            oStreamWriter.WriteLine("sqlcmd -S " + m_Database.DataSourceName + " -d " + m_Database.DatabaseName + " -E -i \"%DB_BASE_DIR%" + oSchema.ShortFileName + "\"");
        //        }
        //        // xmlschemas are not included in the dependency tree
        //        foreach (SOXmlSchema oSchema in this.m_ParentSysObjects.XmlSchemas)
        //        {
        //            oStreamWriter.WriteLine("sqlcmd -S " + m_Database.DataSourceName + " -d " + m_Database.DatabaseName + " -E -i \"%DB_BASE_DIR%" + oSchema.ShortFileName + "\"");
        //        }
        //        // xmlschemas are not included in the dependency tree
        //        foreach (SOUser oUser in this.m_ParentSysObjects.Users)
        //        {
        //            //if (this.m_ParentSysObjects.ScriptOptions.ScriptUsers &&
        //            //    this.m_ParentSysObjects.ScriptOptions.MustScriptUser(oUser.Name))
        //            //{
        //            //    oStreamWriter.WriteLine("sqlcmd -S " + m_Database.DataSourceName + " -d " + m_Database.DatabaseName + " -E -i \"%DB_BASE_DIR%" + oUser.ShortFileName + "\"");
        //            //}
        //        }


        //        // tables first
        //        foreach (SysObject oSysObject in this.m_DependencyTree)
        //        {
        //            switch (oSysObject.Type)
        //            {
        //                //case SysObjectType.View:
        //                //    if (this.m_ParentSysObjects.ScriptOptions.ScriptViews &&
        //                //        this.m_ParentSysObjects.ScriptOptions.MustScriptView(oSysObject.Name))
        //                //    {
        //                //        oStreamWriter.WriteLine("sqlcmd -S " + m_Database.DataSourceName + " -d " + m_Database.DatabaseName + " -E -i \"%DB_BASE_DIR%" + oSysObject.ShortFileName+ "\"");
        //                //    }
        //                //    break;
        //                //case SysObjectType.Table:
                        
        //                //    if (this.m_ParentSysObjects.ScriptOptions.ScriptTables &&
        //                //        this.m_ParentSysObjects.ScriptOptions.MustScriptTable(oSysObject.Name))
        //                //    {
        //                //        oStreamWriter.WriteLine("sqlcmd -S " + m_Database.DataSourceName + " -d " + m_Database.DatabaseName + " -E -i \"%DB_BASE_DIR%" + oSysObject.ShortFileName + "\"");
        //                //    }
        //                //    if (this.m_ParentSysObjects.ScriptOptions.ScriptData &&
        //                //        this.m_ParentSysObjects.ScriptOptions.MustScriptData(oSysObject.Name))
        //                //    {
        //                //        oStreamWriter.WriteLine(strBaseBinDir 
        //                //            + "\\DBSourceDataLoader.exe "
        //                //            + UserSettings.Instance().ProjectBaseDirectory + " "
        //                //            + sourceDatabase.NickName + " "
        //                //            + this.m_Database.NickName + " \"" + oSysObject.Name + "\" "
        //                //            + "\"" + strDatabasesXmlFile + "\"");

        //                //    }
        //                //    break;
        //                //case SysObjectType.Proc:
        //                //    if (this.m_ParentSysObjects.ScriptOptions.ScriptStoredProcs &&
        //                //        this.m_ParentSysObjects.ScriptOptions.MustScriptProc(oSysObject.Name))
        //                //    {
        //                //        oStreamWriter.WriteLine("sqlcmd -S " + m_Database.DataSourceName + " -d " + m_Database.DatabaseName + " -E -i \"%DB_BASE_DIR%" + oSysObject.ShortFileName + "\"");
        //                //    }
        //                //    break;
        //                //default:
        //                //    oStreamWriter.WriteLine("sqlcmd -S " + m_Database.DataSourceName + " -d " + m_Database.DatabaseName + " -E -i \"%DB_BASE_DIR%" + oSysObject.ShortFileName + "\"");
        //                //    break;
        //            }
        //        }

        //    }

        //}

        #region IDisplayPanel Members

        public System.Windows.Forms.Panel GetPanel()
        {
            System.Data.DataTable oDataTable = new System.Data.DataTable();
            
            oDataTable.Columns.Add("Type", typeof(string));
            oDataTable.Columns.Add("Qualified Name", typeof(string));

            foreach (SysObject oSysObject in this.m_DependencyTree)
            {
                if (oSysObject != null)
                {
                    System.Data.DataRow newRow = oDataTable.NewRow();
                    newRow["Type"] = oSysObject.Type.ToString();
                    newRow["Qualified Name"] = oSysObject.Name;
                    oDataTable.Rows.Add(newRow);
                }
            }


            Panel oPanel = new Panel();
            oPanel.Dock = DockStyle.Fill;
            DataGridView oDataGridView = new DataGridView();
            //oDataGridView.ShowEditingIcon = false;
            oDataGridView.AllowUserToAddRows = false;
            //oDataGridView.Sh
            
            oDataGridView.ReadOnly = true;

            DataGridViewTextBoxColumn oColType = new DataGridViewTextBoxColumn();
            oColType.HeaderText = "Type";
            oColType.ReadOnly = true;
            oColType.Name = "Type";
            oColType.DataPropertyName = "Type";
            oColType.SortMode = DataGridViewColumnSortMode.NotSortable;
            //oColType.Width = 300;
            oDataGridView.Columns.Add(oColType);

            DataGridViewTextBoxColumn oColName = new DataGridViewTextBoxColumn();
            oColName.HeaderText = "Qualified Name";
            oColName.ReadOnly = true;
            oColName.Name = "Qualified Name";
            oColName.DataPropertyName = "Qualified Name";
            oColName.Width = 500;
            oColName.SortMode = DataGridViewColumnSortMode.NotSortable;
            oDataGridView.Columns.Add(oColName);

            oDataGridView.DataSource = oDataTable;
            
            oDataGridView.Dock = DockStyle.Fill;
                        
            oPanel.Controls.Add(oDataGridView);
            return oPanel;
            
        }

        #endregion

        internal void Clone(SODependencyTree sourceSODependencyTree)
        {
            foreach (SysObject oSysObject in sourceSODependencyTree.DependencyTree)
            {
                SysObject mySysObject = m_ParentSysObjects.getSysObject(oSysObject.Type.ToString() + "s", oSysObject.Name);
                this.m_DependencyTree.Add(mySysObject);
            }
        }

        internal bool HasErrors()
        {
            return (m_ErrorList.Count > 0 ? true : false);
        }

        internal string GetErrors()
        {
            StringBuilder oBuilder = new StringBuilder();
            oBuilder.AppendLine("Dependency tree errors :");
            foreach( string oErrLine in m_ErrorList) {
                oBuilder.AppendLine(oErrLine);
            }
            return oBuilder.ToString();
        }
    }
}
